package com.zzedu.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.zzedu.common.annotation.DataScope;
import com.zzedu.common.core.domain.entity.SysRole;
import com.zzedu.common.core.domain.entity.SysUser;
import com.zzedu.common.exception.ServiceException;
import com.zzedu.common.utils.SecurityUtils;
import com.zzedu.common.utils.StringUtils;
import com.zzedu.common.utils.spring.SpringUtils;
import com.zzedu.system.domain.SysRoleDept;
import com.zzedu.system.domain.SysRoleMenu;
import com.zzedu.system.domain.SysUserRole;
import com.zzedu.system.mapper.SysRoleDeptMapper;
import com.zzedu.system.mapper.SysRoleMapper;
import com.zzedu.system.mapper.SysRoleMenuMapper;
import com.zzedu.system.service.ISysRoleService;
import com.zzedu.system.service.ISysUserRoleService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 角色 业务层处理
 *
 * @author smarthome
 */
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {

    @Autowired
    ISysUserRoleService sysUserRoleService;

    @Autowired
    SysRoleDeptMapper roleDeptMapper;

    @Autowired
    SysRoleMenuMapper sysRoleMenuMapper;

    @Override
    @DataScope(deptAlias = "d")
    public IPage<SysRole> selectRoleList(SysRole role) {
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery(SysRole.class);
        queryWrapper.eq(null != role.getId(), SysRole::getId, role.getId());
        queryWrapper.eq(null != role.getStatus(), SysRole::getStatus, role.getStatus());
        queryWrapper.eq(null != role.getDataScope(), SysRole::getDataScope, role.getDataScope());
        queryWrapper.like(StringUtils.isNotEmpty(role.getRoleKey()), SysRole::getRoleKey, role.getRoleKey());
        queryWrapper.like(StringUtils.isNotEmpty(role.getRoleName()), SysRole::getRoleName, role.getRoleName());
        queryWrapper.orderByDesc(SysRole::getRoleSort, SysRole::getId);
        return this.page(role.getPageDTO(), queryWrapper);
    }

    /**
     * 根据用户ID查询角色
     *
     * @param userId 用户ID
     * @return 角色列表
     */
    @Override
    public List<SysRole> selectRolesByUserId(Long userId) {
        // SELECT id,role_name,role_key,role_sort,data_scope,status,menu_check_strictly,dept_check_strictly,gmt_create,gmt_modify,deleted,create_by,update_by FROM sys_role WHERE deleted=0 AND (id in(select role_id from sys_user_role where user_id in(select id from sys_user where deleted=0 and id=? and dept_id in(select id from sys_dept where deleted=0))))
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery(SysRole.class);
        queryWrapper.apply("id in(select role_id from sys_user_role where deleted=0 and user_id={0})", userId);
        return this.list(queryWrapper);
    }

    @Override
    public Set<String> selectRolePermissionByUserId(Long userId) {
        List<SysRole> perms = selectRolesByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (SysRole perm : perms) {
            if (StringUtils.isNotNull(perm)) {
                permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
            }
        }
        return permsSet;
    }

    @Override
    public List<SysRole> selectRoleAll() {
        return this.list();
    }

    public List<Long> selectRoleListByUserId(Long userId) {
//        select r.role_id
//        from sys_role r
//        left join sys_user_role ur on ur.role_id = r.role_id
//        left join sys_user u on u.user_id = ur.user_id
//        where u.user_id = #{userId}
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery(SysRole.class);
        queryWrapper.apply("id in(select role_id from sys_user_role where user_id in(select id from sys_user where deleted=0 and id={0} ))", userId);
        return Optional.ofNullable(this.list(queryWrapper)).orElse(Lists.newArrayList()).stream().map(SysRole::getId).collect(Collectors.toList());
    }

    /**
     * 通过角色ID查询角色
     *
     * @param roleId 角色ID
     * @return 角色对象信息
     */
    public SysRole selectRoleById(Long id) {
        return getById(id);
    }

    /**
     * 校验角色名称是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    public boolean checkRoleNameUnique(SysRole role) {
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery(SysRole.class);
        queryWrapper.eq(SysRole::getRoleName, role.getRoleName());
        return count(queryWrapper) > 0;
    }

    /**
     * 校验角色权限是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    public boolean checkRoleKeyUnique(SysRole role) {
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery(SysRole.class);
        queryWrapper.eq(SysRole::getRoleKey, role.getRoleKey());
        return count(queryWrapper) > 0;
    }

    /**
     * 校验角色是否允许操作
     *
     * @param role 角色信息
     */
    public void checkRoleAllowed(SysRole role) {
        if (StringUtils.isNotNull(role.getId()) && role.isAdmin()) {
            throw new ServiceException("不允许操作超级管理员角色");
        }
    }

    /**
     * 校验角色是否有数据权限
     *
     * @param roleIds 角色id
     */
    public void checkRoleDataScope(Long... roleIds) {
        if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
            for (Long roleId : roleIds) {
                SysRole role = new SysRole();
                role.setId(roleId);
                IPage<SysRole> page = SpringUtils.getAopProxy(this).selectRoleList(role);
                if (null == page || CollectionUtils.isEmpty(page.getRecords())) {
                    throw new ServiceException("没有权限访问角色数据！");
                }
            }
        }
    }

    /**
     * 通过角色ID查询角色使用数量
     *
     * @param roleId 角色ID
     * @return 结果
     */
    public long countUserRoleByRoleId(Long roleId) {
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery(SysRole.class);
        queryWrapper.eq(SysRole::getId, roleId);
        return count(queryWrapper);
    }

    /**
     * 新增保存角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    public int insertRole(SysRole role) {
        save(role);
        if (CollectionUtils.isNotEmpty(role.getMenuIds())) {
            for (Long mid : role.getMenuIds()) {
                SysRoleMenu sysRoleMenu = new SysRoleMenu();
                sysRoleMenu.setMenuId(mid);
                sysRoleMenu.setRoleId(role.getId());
                sysRoleMenuMapper.insert(sysRoleMenu);
            }
        }
        return 1;
    }

    /**
     * 修改保存角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    public int updateRole(SysRole role) {
        updateById(role);
        sysRoleMenuMapper.delete(Wrappers.lambdaQuery(SysRoleMenu.class)
                .eq(SysRoleMenu::getRoleId, role.getId()));
        if (CollectionUtils.isNotEmpty(role.getMenuIds())) {
            for (Long mid : role.getMenuIds()) {
                SysRoleMenu sysRoleMenu = new SysRoleMenu();
                sysRoleMenu.setMenuId(mid);
                sysRoleMenu.setRoleId(role.getId());
                sysRoleMenuMapper.insert(sysRoleMenu);
            }
        }

        return 1;
    }

    /**
     * 修改角色状态
     *
     * @param role 角色信息
     * @return 结果
     */
    public int updateRoleStatus(SysRole role) {
        updateById(role);
        return 1;
    }


    /**
     * 修改数据权限信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Transactional(readOnly = false)
    public int authDataScope(SysRole role) {
        updateById(role);
        // 删除角色与部门关联
        roleDeptMapper.delete(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getRoleId, role.getId()));
        // 新增角色和部门信息（数据权限）
        List<SysRoleDept> list = new ArrayList<SysRoleDept>();
        for (Long deptId : role.getDeptIds()) {
            SysRoleDept rd = new SysRoleDept();
            rd.setRoleId(role.getId());
            rd.setDeptId(deptId);
            roleDeptMapper.insert(rd);
        }
        return 1;
    }

    /**
     * 通过角色ID删除角色
     *
     * @param roleId 角色ID
     * @return 结果
     */
    public int deleteRoleById(Long roleId) {
        removeById(roleId);
        return 1;
    }

    /**
     * 批量删除角色信息
     *
     * @param roleIds 需要删除的角色ID
     * @return 结果
     */
    public int deleteRoleByIds(Long[] roleIds) {
        removeBatchByIds(Arrays.stream(roleIds).collect(Collectors.toList()));
        return 1;
    }


    /**
     * 取消授权用户角色
     *
     * @param userRole 用户和角色关联信息
     * @return 结果
     */
    public int deleteAuthUser(SysUserRole userRole) {
// 		delete from sys_user_role where user_id=#{userId} and role_id=#{roleId}
        this.sysUserRoleService.remove(Wrappers.lambdaQuery(SysUserRole.class)
                .eq(SysUserRole::getRoleId, userRole.getRoleId())
                .eq(SysUserRole::getUserId, userRole.getUserId())
        );
        return 1;
    }

    /**
     * 批量取消授权用户角色
     *
     * @param roleId  角色ID
     * @param userIds 需要取消授权的用户数据ID
     * @return 结果
     */
    public int deleteAuthUsers(Long roleId, Long[] userIds) {
        this.sysUserRoleService.remove(Wrappers.lambdaQuery(SysUserRole.class)
                .eq(SysUserRole::getRoleId, roleId)
                .in(SysUserRole::getUserId, userIds)
        );
        return 1;
    }

    /**
     * 批量选择授权用户角色
     *
     * @param roleId  角色ID
     * @param userIds 需要删除的用户数据ID
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class, readOnly = false)
    public int insertAuthUsers(Long roleId, Long[] userIds) {
        for (Long uid : userIds) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setRoleId(roleId);
            sysUserRole.setUserId(uid);
            sysUserRoleService.save(sysUserRole);
        }
        return 1;
    }
}
